home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 83 / MacAddict_083_2003-07.iso / mac / Software / Development / VLC Source 0.5.3.dmg / src / input / input_ext-plugins.c < prev    next >
C/C++ Source or Header  |  2003-04-07  |  21KB  |  646 lines

  1. /*****************************************************************************
  2.  * input_ext-plugins.c: useful functions for access and demux plug-ins
  3.  *****************************************************************************
  4.  * Copyright (C) 2001, 2002 VideoLAN
  5.  * $Id: input_ext-plugins.c,v 1.31 2003/03/24 17:15:30 gbazin Exp $
  6.  *
  7.  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  * 
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23.  
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #include <stdlib.h>
  28. #include <string.h>
  29.  
  30. #include <vlc/vlc.h>
  31.  
  32. #include "stream_control.h"
  33. #include "input_ext-intf.h"
  34. #include "input_ext-dec.h"
  35. #include "input_ext-plugins.h"
  36.  
  37.  
  38. /*
  39.  * Buffers management : internal functions
  40.  *
  41.  * All functions are static, but exported versions with mutex protection
  42.  * start with input_*. Not all of these exported functions are actually used,
  43.  * but they are included here for completeness.
  44.  */
  45.  
  46. #define BUFFERS_CACHE_SIZE 500
  47. #define DATA_CACHE_SIZE 1000
  48. #define PES_CACHE_SIZE 1000
  49.  
  50. /*****************************************************************************
  51.  * data_buffer_t: shared data type
  52.  *****************************************************************************/
  53. struct data_buffer_t
  54. {
  55.     data_buffer_t * p_next;
  56.  
  57.     /* number of data packets this buffer is referenced from - when it falls
  58.      * down to 0, the buffer is freed */
  59.     int i_refcount;
  60.  
  61.     /* size of the current buffer (starting right after this byte) */
  62.     size_t i_size;
  63. };
  64.  
  65. /*****************************************************************************
  66.  * input_buffers_t: defines a LIFO per data type to keep
  67.  *****************************************************************************/
  68. #define PACKETS_LIFO( TYPE, NAME )                                          \
  69. struct                                                                      \
  70. {                                                                           \
  71.     TYPE * p_stack;                                                         \
  72.     unsigned int i_depth;                                                   \
  73. } NAME;
  74.  
  75. struct input_buffers_t
  76. {
  77.     vlc_mutex_t lock;
  78.     PACKETS_LIFO( pes_packet_t, pes )
  79.     PACKETS_LIFO( data_packet_t, data )
  80.     PACKETS_LIFO( data_buffer_t, buffers )
  81.     size_t i_allocated;
  82. };
  83.  
  84.  
  85. /*****************************************************************************
  86.  * input_BuffersInit: initialize the cache structures, return a pointer to it
  87.  *****************************************************************************/
  88. void * __input_BuffersInit( vlc_object_t *p_this )
  89. {
  90.     input_buffers_t * p_buffers = malloc( sizeof( input_buffers_t ) );
  91.  
  92.     if( p_buffers == NULL )
  93.     {
  94.         return NULL;
  95.     }
  96.  
  97.     memset( p_buffers, 0, sizeof( input_buffers_t ) );
  98.     vlc_mutex_init( p_this, &p_buffers->lock );
  99.  
  100.     return p_buffers;
  101. }
  102.  
  103. /*****************************************************************************
  104.  * input_BuffersEnd: free all cached structures
  105.  *****************************************************************************/
  106. #define BUFFERS_END_PACKETS_LOOP                                            \
  107.     while( p_packet != NULL )                                               \
  108.     {                                                                       \
  109.         p_next = p_packet->p_next;                                          \
  110.         free( p_packet );                                                   \
  111.         p_packet = p_next;                                                  \
  112.     }
  113.  
  114. void input_BuffersEnd( input_thread_t * p_input, input_buffers_t * p_buffers )
  115. {
  116.     if( p_buffers != NULL )
  117.     {
  118.         msg_Dbg( p_input, "pes: %d packets", p_buffers->pes.i_depth );
  119.         msg_Dbg( p_input, "data: %d packets", p_buffers->data.i_depth );
  120.         msg_Dbg( p_input, "buffers: %d packets", p_buffers->buffers.i_depth );
  121.  
  122.         {
  123.             /* Free PES */
  124.             pes_packet_t * p_next, * p_packet = p_buffers->pes.p_stack;
  125.             BUFFERS_END_PACKETS_LOOP;
  126.         }
  127.  
  128.         {
  129.             /* Free data packets */
  130.             data_packet_t * p_next, * p_packet = p_buffers->data.p_stack;
  131.             BUFFERS_END_PACKETS_LOOP;
  132.         }
  133.  
  134.         {
  135.             /* Free buffers */
  136.             data_buffer_t * p_next, * p_buf = p_buffers->buffers.p_stack;
  137.             while( p_buf != NULL )
  138.             {
  139.                 p_next = p_buf->p_next;
  140.                 p_buffers->i_allocated -= p_buf->i_size;
  141.                 free( p_buf );
  142.                 p_buf = p_next;
  143.             }
  144.         } 
  145.  
  146.         if( p_buffers->i_allocated )
  147.         {
  148.             msg_Err( p_input, "%u bytes have not been freed, "
  149.                               "expect memory leak", p_buffers->i_allocated );
  150.         }
  151.  
  152.         vlc_mutex_destroy( &p_buffers->lock );
  153.         free( p_buffers );
  154.     }
  155. }
  156.  
  157. /*****************************************************************************
  158.  * input_NewBuffer: return a pointer to a data buffer of the appropriate size
  159.  *****************************************************************************/
  160. static inline data_buffer_t * NewBuffer( input_buffers_t * p_buffers,
  161.                                          size_t i_size,
  162.                                          vlc_bool_t b_forced )
  163. {
  164.     data_buffer_t * p_buf;
  165.  
  166.     /* Safety check */
  167.     if( !b_forced && p_buffers->i_allocated > INPUT_MAX_ALLOCATION )
  168.     {
  169.         return NULL;
  170.     }
  171.  
  172.     if( p_buffers->buffers.p_stack != NULL )
  173.     {
  174.         /* Take the buffer from the cache */
  175.         p_buf = p_buffers->buffers.p_stack;
  176.         p_buffers->buffers.p_stack = p_buf->p_next;
  177.         p_buffers->buffers.i_depth--;
  178.  
  179.         /* Reallocate the packet if it is too small or too large */
  180.         if( p_buf->i_size < i_size || p_buf->i_size > 3 * i_size )
  181.         {
  182.             p_buffers->i_allocated -= p_buf->i_size;
  183.             free( p_buf );
  184.             p_buf = malloc( sizeof(input_buffers_t) + i_size );
  185.             if( p_buf == NULL )
  186.             {
  187.                 return NULL;
  188.             }
  189.             p_buf->i_size = i_size;
  190.             p_buffers->i_allocated += i_size;
  191.         }
  192.     }
  193.     else
  194.     {
  195.         /* Allocate a new buffer */
  196.         p_buf = malloc( sizeof(input_buffers_t) + i_size );
  197.         if( p_buf == NULL )
  198.         {
  199.             return NULL;
  200.         }
  201.         p_buf->i_size = i_size;
  202.         p_buffers->i_allocated += i_size;
  203.     }
  204.  
  205.     /* Initialize data */
  206.     p_buf->p_next = NULL;
  207.     p_buf->i_refcount = 0;
  208.  
  209.     return p_buf;
  210. }
  211.  
  212. data_buffer_t * input_NewBuffer( input_buffers_t * p_buffers, size_t i_size )
  213. {
  214.     data_buffer_t * p_buf;
  215.  
  216.     vlc_mutex_lock( &p_buffers->lock );
  217.     p_buf = NewBuffer( p_buffers, i_size, VLC_FALSE );
  218.     vlc_mutex_unlock( &p_buffers->lock );
  219.  
  220.     return p_buf;
  221. }
  222.  
  223. /*****************************************************************************
  224.  * input_ReleaseBuffer: put a buffer back into the cache
  225.  *****************************************************************************/
  226. static inline void ReleaseBuffer( input_buffers_t * p_buffers,
  227.                                   data_buffer_t * p_buf )
  228. {
  229.     /* Decrement refcount */
  230.     if( --p_buf->i_refcount > 0 )
  231.     {
  232.         return;
  233.     }
  234.  
  235.     if( p_buffers->buffers.i_depth < BUFFERS_CACHE_SIZE )
  236.     {
  237.         /* Cache not full : store the buffer in it */
  238.         p_buf->p_next = p_buffers->buffers.p_stack;
  239.         p_buffers->buffers.p_stack = p_buf;
  240.         p_buffers->buffers.i_depth++;
  241.     }
  242.     else
  243.     {
  244.         p_buffers->i_allocated -= p_buf->i_size;
  245.         free( p_buf );
  246.     }
  247. }
  248.  
  249. void input_ReleaseBuffer( input_buffers_t * p_buffers, data_buffer_t * p_buf )
  250. {
  251.     vlc_mutex_lock( &p_buffers->lock );
  252.     ReleaseBuffer( p_buffers, p_buf );
  253.     vlc_mutex_unlock( &p_buffers->lock );
  254. }
  255.  
  256. /*****************************************************************************
  257.  * input_ShareBuffer: allocate a data_packet_t pointing to a given buffer
  258.  *****************************************************************************/
  259. static inline data_packet_t * ShareBuffer( input_buffers_t * p_buffers,
  260.                                            data_buffer_t * p_buf )
  261. {
  262.     data_packet_t * p_data;
  263.  
  264.     if( p_buffers->data.p_stack != NULL )
  265.     {
  266.         /* Take the packet from the cache */
  267.         p_data = p_buffers->data.p_stack;
  268.         p_buffers->data.p_stack = p_data->p_next;
  269.         p_buffers->data.i_depth--;
  270.     }
  271.     else
  272.     {
  273.         /* Allocate a new packet */
  274.         p_data = malloc( sizeof(data_packet_t) );
  275.         if( p_data == NULL )
  276.         {
  277.             return NULL;
  278.         }
  279.     }
  280.  
  281.     p_data->p_buffer = p_buf;
  282.     p_data->p_next = NULL;
  283.     p_data->b_discard_payload = 0;
  284.     p_data->p_payload_start = p_data->p_demux_start
  285.                             = (byte_t *)p_buf + sizeof(input_buffers_t);
  286.     p_data->p_payload_end = p_data->p_demux_start + p_buf->i_size;
  287.     p_buf->i_refcount++;
  288.  
  289.     return p_data;
  290. }
  291.  
  292. data_packet_t * input_ShareBuffer( input_buffers_t * p_buffers,
  293.                                    data_buffer_t * p_buf )
  294. {
  295.     data_packet_t * p_data;
  296.  
  297.     vlc_mutex_lock( &p_buffers->lock );
  298.     p_data = ShareBuffer( p_buffers, p_buf );
  299.     vlc_mutex_unlock( &p_buffers->lock );
  300.  
  301.     return p_data;
  302. }
  303.  
  304. /*****************************************************************************
  305.  * input_NewPacket: allocate a packet along with a buffer
  306.  *****************************************************************************/
  307. static inline data_packet_t * NewPacket( input_buffers_t * p_buffers,
  308.                                          size_t i_size,
  309.                                          vlc_bool_t b_forced )
  310. {
  311.     data_buffer_t * p_buf;
  312.     data_packet_t * p_data;
  313.  
  314.     p_buf = NewBuffer( p_buffers, i_size, b_forced );
  315.  
  316.     if( p_buf == NULL )
  317.     {
  318.         return NULL;
  319.     }
  320.  
  321.     p_data = ShareBuffer( p_buffers, p_buf );
  322.     if( p_data == NULL )
  323.     {
  324.         ReleaseBuffer( p_buffers, p_buf );
  325.     }
  326.     return p_data;
  327. }
  328.  
  329. data_packet_t * input_NewPacket( input_buffers_t * p_buffers, size_t i_size )
  330. {
  331.     data_packet_t * p_data;
  332.  
  333.     vlc_mutex_lock( &p_buffers->lock );
  334.     p_data = NewPacket( p_buffers, i_size, VLC_FALSE );
  335.     vlc_mutex_unlock( &p_buffers->lock );
  336.  
  337.     return p_data;
  338. }
  339.  
  340. data_packet_t * input_NewPacketForce( input_buffers_t * p_buffers, size_t i_size )
  341. {
  342.     data_packet_t * p_data;
  343.  
  344.     vlc_mutex_lock( &p_buffers->lock );
  345.     p_data = NewPacket( p_buffers, i_size, VLC_TRUE);
  346.     vlc_mutex_unlock( &p_buffers->lock );
  347.  
  348.     return p_data;
  349. }
  350.  
  351. /*****************************************************************************
  352.  * input_DeletePacket: deallocate a packet and its buffers
  353.  *****************************************************************************/
  354. static inline void DeletePacket( input_buffers_t * p_buffers,
  355.                                  data_packet_t * p_data )
  356. {
  357.     while( p_data != NULL )
  358.     {
  359.         data_packet_t * p_next = p_data->p_next;
  360.  
  361.         ReleaseBuffer( p_buffers, p_data->p_buffer );
  362.  
  363.         if( p_buffers->data.i_depth < DATA_CACHE_SIZE )
  364.         {
  365.             /* Cache not full : store the packet in it */
  366.             p_data->p_next = p_buffers->data.p_stack;
  367.             p_buffers->data.p_stack = p_data;
  368.             p_buffers->data.i_depth++;
  369.         }
  370.         else
  371.         {
  372.             free( p_data );
  373.         }
  374.  
  375.         p_data = p_next;
  376.     }
  377. }
  378.  
  379. void input_DeletePacket( input_buffers_t * p_buffers, data_packet_t * p_data )
  380. {
  381.     vlc_mutex_lock( &p_buffers->lock );
  382.     DeletePacket( p_buffers, p_data );
  383.     vlc_mutex_unlock( &p_buffers->lock );
  384. }
  385.  
  386. /*****************************************************************************
  387.  * input_NewPES: return a pointer to a new PES packet
  388.  *****************************************************************************/
  389. static inline pes_packet_t * NewPES( input_buffers_t * p_buffers )
  390. {
  391.     pes_packet_t * p_pes;
  392.  
  393.     if( p_buffers->pes.p_stack != NULL )
  394.     {
  395.         /* Take the packet from the cache */
  396.         p_pes = p_buffers->pes.p_stack;
  397.         p_buffers->pes.p_stack = p_pes->p_next;
  398.         p_buffers->pes.i_depth--;
  399.     }
  400.     else
  401.     {
  402.         /* Allocate a new packet */
  403.         p_pes = malloc( sizeof(pes_packet_t) );
  404.         if( p_pes == NULL )
  405.         {
  406.             return NULL;
  407.         }
  408.     }
  409.  
  410.     p_pes->p_next = NULL;
  411.     p_pes->b_data_alignment = p_pes->b_discontinuity = VLC_FALSE;
  412.     p_pes->i_pts = p_pes->i_dts = 0;
  413.     p_pes->p_first = p_pes->p_last = NULL;
  414.     p_pes->i_pes_size = 0;
  415.     p_pes->i_nb_data = 0;
  416.  
  417.     return p_pes;
  418. }
  419.  
  420. pes_packet_t * input_NewPES( input_buffers_t * p_buffers )
  421. {
  422.     pes_packet_t * p_pes;
  423.  
  424.     vlc_mutex_lock( &p_buffers->lock );
  425.     p_pes = NewPES( p_buffers );
  426.     vlc_mutex_unlock( &p_buffers->lock );
  427.  
  428.     return p_pes;
  429. }
  430.  
  431. /*****************************************************************************
  432.  * input_DeletePES: put a pes and all data packets and all buffers back into
  433.  *                  the cache
  434.  *****************************************************************************/
  435. static inline void DeletePES( input_buffers_t * p_buffers,
  436.                               pes_packet_t * p_pes )
  437. {
  438.     while( p_pes != NULL )
  439.     {
  440.         pes_packet_t * p_next = p_pes->p_next;
  441.  
  442.         /* Delete all data packets */
  443.         if( p_pes->p_first != NULL )
  444.         {
  445.             DeletePacket( p_buffers, p_pes->p_first );
  446.         }
  447.  
  448.         if( p_buffers->pes.i_depth < PES_CACHE_SIZE )
  449.         {
  450.             /* Cache not full : store the packet in it */
  451.             p_pes->p_next = p_buffers->pes.p_stack;
  452.             p_buffers->pes.p_stack = p_pes;
  453.             p_buffers->pes.i_depth++;
  454.         }
  455.         else
  456.         {
  457.             free( p_pes );
  458.         }
  459.  
  460.         p_pes = p_next;
  461.     }
  462. }
  463.  
  464. void input_DeletePES( input_buffers_t * p_buffers, pes_packet_t * p_pes )
  465. {
  466.     vlc_mutex_lock( &p_buffers->lock );
  467.     DeletePES( p_buffers, p_pes );
  468.     vlc_mutex_unlock( &p_buffers->lock );
  469. }
  470.  
  471.  
  472. /*
  473.  * Buffers management : external functions
  474.  *
  475.  * These functions make the glu between the access plug-in (pf_read) and
  476.  * the demux plug-in (pf_demux). We fill in a large buffer (approx. 10s kB)
  477.  * with a call to pf_read, then allow the demux plug-in to have a peep at
  478.  * it (input_Peek), and to split it in data_packet_t (input_SplitBuffer).
  479.  */
  480. /*****************************************************************************
  481.  * input_FillBuffer: fill in p_data_buffer with data from pf_read
  482.  *****************************************************************************/
  483. ssize_t input_FillBuffer( input_thread_t * p_input )
  484. {
  485.     ptrdiff_t i_remains = p_input->p_last_data - p_input->p_current_data;
  486.     data_buffer_t * p_buf;
  487.     ssize_t i_ret;
  488.  
  489.     vlc_mutex_lock( &p_input->p_method_data->lock );
  490.  
  491.     p_buf = NewBuffer( p_input->p_method_data,
  492.                        i_remains + p_input->i_bufsize, VLC_FALSE );
  493.     if( p_buf == NULL )
  494.     {
  495.         vlc_mutex_unlock( &p_input->p_method_data->lock );
  496.         msg_Err( p_input, "failed allocating a new buffer (decoder stuck?)" );
  497.         msleep( INPUT_IDLE_SLEEP );
  498.         return -1;
  499.     }
  500.     p_buf->i_refcount = 1;
  501.  
  502.     if( p_input->p_data_buffer != NULL )
  503.     {
  504.         if( i_remains )
  505.         {
  506.             p_input->p_vlc->pf_memcpy( (byte_t *)p_buf + sizeof(data_buffer_t),
  507.                                        p_input->p_current_data,
  508.                                        (size_t)i_remains );
  509.         }
  510.         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
  511.     }
  512.  
  513.     /* Do not hold the lock during pf_read (blocking call). */
  514.     vlc_mutex_unlock( &p_input->p_method_data->lock );
  515.  
  516.     i_ret = p_input->pf_read( p_input,
  517.                               (byte_t *)p_buf + sizeof(data_buffer_t)
  518.                                + i_remains,
  519.                               p_input->i_bufsize );
  520.     if( i_ret < 0 && i_remains == 0 )
  521.     {
  522.         /* Our internal buffers are empty, we can signal the error */
  523.         return -1;
  524.     }
  525.  
  526.     if( i_ret < 0 ) i_ret = 0;
  527.  
  528.     p_input->p_data_buffer = p_buf;
  529.     p_input->p_current_data = (byte_t *)p_buf + sizeof(data_buffer_t);
  530.     p_input->p_last_data = p_input->p_current_data + i_remains + i_ret;
  531.  
  532.     return (ssize_t)i_remains + i_ret;
  533. }
  534.  
  535. /*****************************************************************************
  536.  * input_Peek: give a pointer to the next available bytes in the buffer
  537.  *             (min. i_size bytes)
  538.  * Returns the number of bytes read, or -1 in case of error
  539.  *****************************************************************************/
  540. ssize_t input_Peek( input_thread_t * p_input, byte_t ** pp_byte, size_t i_size )
  541. {
  542.     if( p_input->p_last_data - p_input->p_current_data < (ptrdiff_t)i_size )
  543.     {
  544.         /* Go to the next buffer */
  545.         ssize_t i_ret = input_FillBuffer( p_input );
  546.  
  547.         if( i_ret < 0 )
  548.         {
  549.             return -1;
  550.         }
  551.  
  552.         if( i_ret < (ssize_t)i_size )
  553.         {
  554.             i_size = i_ret;
  555.         }
  556.     }
  557.     *pp_byte = p_input->p_current_data;
  558.     return i_size;
  559. }
  560.  
  561. /*****************************************************************************
  562.  * input_SplitBuffer: give a pointer to a data packet containing i_size bytes
  563.  * Returns the number of bytes read, or -1 in case of error
  564.  *****************************************************************************/
  565. ssize_t input_SplitBuffer( input_thread_t * p_input,
  566.                            data_packet_t ** pp_data, size_t i_size )
  567. {
  568.     if( p_input->p_last_data - p_input->p_current_data < (ptrdiff_t)i_size )
  569.     {
  570.         /* Go to the next buffer */
  571.         ssize_t i_ret = input_FillBuffer( p_input );
  572.  
  573.         if( i_ret < 0 )
  574.         {
  575.             return -1;
  576.         }
  577.  
  578.         if( i_ret < (ssize_t)i_size )
  579.         {
  580.             i_size = i_ret;
  581.         }
  582.     }
  583.  
  584.     if ( !i_size )
  585.     {
  586.         return 0;
  587.     }
  588.  
  589.     *pp_data = input_ShareBuffer( p_input->p_method_data,
  590.                                   p_input->p_data_buffer );
  591.  
  592.     (*pp_data)->p_demux_start = (*pp_data)->p_payload_start
  593.         = p_input->p_current_data;
  594.     (*pp_data)->p_payload_end = (*pp_data)->p_demux_start + i_size;
  595.  
  596.     p_input->p_current_data += i_size;
  597.  
  598.     /* Update stream position */
  599.     vlc_mutex_lock( &p_input->stream.stream_lock );
  600.     p_input->stream.p_selected_area->i_tell += i_size;
  601.     vlc_mutex_unlock( &p_input->stream.stream_lock );
  602.  
  603.     return i_size;
  604. }
  605.  
  606. /*****************************************************************************
  607.  * input_AccessInit: initialize access plug-in wrapper structures
  608.  *****************************************************************************/
  609. int input_AccessInit( input_thread_t * p_input )
  610. {
  611.     p_input->p_method_data = input_BuffersInit( p_input );
  612.     if( p_input->p_method_data == NULL ) return -1;
  613.     p_input->p_data_buffer = NULL;
  614.     p_input->p_current_data = NULL;
  615.     p_input->p_last_data = NULL;
  616.     return 0;
  617. }
  618.  
  619. /*****************************************************************************
  620.  * input_AccessReinit: reinit structures before a random seek
  621.  *****************************************************************************/
  622. void input_AccessReinit( input_thread_t * p_input )
  623. {
  624.     if( p_input->p_data_buffer != NULL )
  625.     {
  626.         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
  627.     }
  628.     p_input->p_data_buffer = NULL;
  629.     p_input->p_current_data = NULL;
  630.     p_input->p_last_data = NULL;
  631. }
  632.  
  633. /*****************************************************************************
  634.  * input_AccessEnd: free access plug-in wrapper structures
  635.  *****************************************************************************/
  636. void input_AccessEnd( input_thread_t * p_input )
  637. {
  638.     if( p_input->p_data_buffer != NULL )
  639.     {
  640.         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
  641.     }
  642.  
  643.     input_BuffersEnd( p_input, p_input->p_method_data );
  644. }
  645.  
  646.